package com.ruoyi.common.filter;

import com.ruoyi.common.utils.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 防止XSS攻击的过滤器
 *
 * @author ruoyi
 */
public class XssFilter implements Filter {
    /**
     * 排除链接
     */
    public List<String> excludes = new ArrayList<>();

    /**
     * xss过滤开关
     */
    public boolean enabled = false;

    /**
     * 初始化过滤器
     *
     * @param filterConfig 过滤器配置
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 获取初始化参数中的排除项和启用状态
        String tempExcludes = filterConfig.getInitParameter("excludes");
        String tempEnabled = filterConfig.getInitParameter("enabled");
        // 如果排除项不为空，则将其按逗号分隔后添加到排除列表中
        if (StringUtils.isNotEmpty(tempExcludes)) {
            String[] url = tempExcludes.split(",");
            for (int i = 0; url != null && i < url.length; i++) {
                excludes.add(url[i]);
            }
        }
        // 如果启用状态不为空，则将其转换为布尔值
        if (StringUtils.isNotEmpty(tempEnabled)) {
            enabled = Boolean.valueOf(tempEnabled);
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;  // 将 request 转换为 HttpServletRequest 类型
        HttpServletResponse resp = (HttpServletResponse) response;  // 将 response 转换为 HttpServletResponse 类型
        if (handleExcludeURL(req, resp))  // 如果请求的 URL 在排除的列表中
        {
            chain.doFilter(request, response);  // 继续执行过滤器链
            return;  // 结束当前方法
        }
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);  // 创建 XssHttpServletRequestWrapper 对象，用于处理请求中的跨站脚本攻击
        chain.doFilter(xssRequest, response);  // 继续执行过滤器链
    }

    /**
     * 判断是否需要排除某个URL，不对其进行XSS过滤
     *
     * @param request  HTTP请求对象
     * @param response HTTP响应对象
     * @return 如果不需要进行XSS过滤，则返回true；否则返回false
     */
    private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
        // 如果XSS过滤未启用，则直接返回true
        if (!enabled) {
            return true;
        }
        // 如果排除列表为空，则不进行排除，返回false
        if (excludes == null || excludes.isEmpty()) {
            return false;
        }
        // 获取请求的URL路径
        String url = request.getServletPath();
        // 遍历排除列表中的URL模式
        for (String pattern : excludes) {
            // 使用正则表达式创建模式匹配器
            Pattern p = Pattern.compile("^" + pattern);
            Matcher m = p.matcher(url);
            // 如果匹配成功，则不进行XSS过滤，返回true
            if (m.find()) {
                return true;
            }
        }
        // 如果未匹配任何排除的URL模式，则进行XSS过滤，返回false
        return false;
    }

    @Override
    public void destroy() {

    }
}